<?php
/**
 * NetWhitepages - PHP Class to use the WhitePages.com API
 * Information on the API and registering to use it can be found at
 * http://developer.whitepages.com.
 *
 * @package NetWhitepages
 * @version 1.0
 * @author Don Shanks <donshanks@gmail.com>
 * @copyright Copyright (c) 2008, Don Shanks
 * @license http://opensource.org/licenses/gpl-3.0.html
 *
 */

define('VERSION','1.0');
define('WP_NAMESPACE','http://api.whitepages.com/schema/');

/**
 * Net_WhitePages - Connection class used to store and retrieve
 *   information from the WhitePages.com API
 */
class Net_WhitePages {
    
	/**
	 * API Base URL
	 */
    private $_api_base    = 'http://api.whitepages.com';
	/**
	 * API Version to use
	 */
    private $_api_version = '1.0';
	/**
	 * The API key used to connect to the API
	 */
    private $_api_key;
	/**
	 * The useragent to call the API with
	 */
    private $_useragent;
    
	/**
	 * Class Constructor
	 *
	 * @param string $key the WhitePages.com API key
	 */
    public function __construct($key) {
        $this->_api_key   = $key;
        $this->_useragent = 'php-net-whitepages/' . VERSION;
    }
    
    /**
     * find_person - performs a find_person search. Uses an array of name-value 
	 *   pairs to create the search parameters. Accepted parameters are: 
	 *   firstname, lastname, house, street, city, state, zip, areacode and metro.
	 *   The parameter 'lastname' is required. More information on the parameters
	 *   can be found on the WhitePages.com developer website.
	 *
	 * @param mixed $params array of variables to pass into the search
	 * @link http://developer.whitepages.com/docs/Methods/find_person
	 * @return Net_WhitePages_Result object
     */
    public function find_person( $params ) {
        return $this->_request( __FUNCTION__, $params );
    }

    /**
     * reverse_phone - performs a reverse_address search. Uses an array of 
	 *   name-value pairs to create the search parameters. Accepted parameters 
	 *   are: phone and state. The parameter 'phone' is required. More information 
	 *   on the parameters can be found on the WhitePages.com developer website.
	 *
	 * @param mixed $params array of variables to pass into the search
     * @link http://developer.whitepages.com/docs/Methods/reverse_phone
	 * @return Net_WhitePages_Result object
     */
    public function reverse_phone( $params ) {
        return $this->_request( __FUNCTION__, $params );
    }

    /**
     * reverse_address - performs a reverse_address search. Uses an array of 
	 *   name-value pairs to create the search parameters. Accepted parameters 
	 *   are: house, apt, street, city, state, zip and areacode. The parameter 
	 *   'street' is required. More information on the parameters can be found 
	 *   on the WhitePages.com developer website.
	 *
	 * @param mixed $params array of variables to pass into the search
     * @link http://developer.whitepages.com/docs/Methods/reverse_address
	 * @return Net_WhitePages_Result object
     */
    public function reverse_address( $params ) {
        return $this->_request( __FUNCTION__, $params );
    }

    /**
	 * _build_uri - creates the url to call the WhitePages.com API.
	 *
	 * @param string $method the WhitePages.com search API method to call
	 * @param mixed $params array of variables to pass into the search
	 * @return string a url to use for the API
     */
    private function _build_uri($method,$params) {
        $uri = join( '/', array($this->_api_base,$method,$this->_api_version) );
        
        $params['api_key'] = $this->_api_key;
        
        $query = http_build_query( $params );
        
        $uri .= "?$query";
        
        return $uri;
    }

    /**
	 * _request - performs a search request to the WhitePages.com API
	 *
	 * @param string $method the WhitePages.com search API method to call
	 * @param mixed $params array of variables to pass into the search
	 * @return Net_WhitePages_Result object
     */
    private function _request($method,$params) {
        $http = curl_init();
        curl_setopt($http, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($http, CURLOPT_URL, $this->_build_uri($method,$params));
        curl_setopt($http, CURLOPT_USERAGENT, $this->_useragent);
        
        $resp = curl_exec($http);
        
        $dom = new DOMDocument('1.0','UTF-8');
        if ( $dom->loadXML($resp) === false ) {
            echo 'Parsing Failed!';
        } else {
            $wp = new Net_WhitePages_Result();
            $wp->load($dom);
            return $wp;
        }
    }
}

/**
 * Net_WhitePages_Result - Object class used to store the retrieved
 *   information from the WhitePages.com API
 */
class Net_WhitePages_Result {
    
	/** 
	 * Storage for the actual DOM response retrieved from the API, 
	 * used when calling toString
	 */
    private $_dom;
	/**
	 * The Request object parameters
	 */
    private $_params;
    
	/**
	 * Class Constructor
	 */
    public function __construct() {
        $this->_params = array();
    }
    
	/**
	 * __toString - override used to dump the response from WhitePages.com
	 *
	 * @return string API response
	 */
    public function __toString() {
        return $this->_dom->saveXML();
    }
    
	/**
	 * __set - override used to set object parameters
	 *
	 * @param string $key name of parameter
	 * @param mixed parameter content
	 */
    public function __set($key,$val) {
        $this->_params[$key] = $val;
    }
    
	/**
	 * __get - override used to set object parameters
	 *
	 * @param string $key name of parameter
	 * @return mixed parameter content
	 */
    public function __get($key) {
        if ( isset( $this->_params[$key] ) ) {
            return $this->_params[$key];
        }
        else {
            return false;
        }
    }
    
	/**
	 * load - loads the response document into an object
	 *
	 * @param - DOMDocument $doc WhitePages.com response document
	 */
    public function load($doc) {
        $this->_dom = $doc;
        
        $root = $this->_dom->firstChild;
        
        $resultNode = $root->getElementsByTagName('result')->item(0);

		    // Result object meta data
        $this->result_type = $resultNode->getAttributeNS(WP_NAMESPACE,'type');
        $this->result_code = $resultNode->getAttributeNS(WP_NAMESPACE,'code');
        
        $metaNode = $root->getElementsByTagName('meta')->item(0);
        
        $this->record_count = $metaNode->getElementsByTagNameNS(WP_NAMESPACE,'recordrange')->item(0)->getAttributeNS(WP_NAMESPACE,'totalavailable');
        
        $searchLinkNode = $metaNode->getElementsByTagNameNS(WP_NAMESPACE,'searchlinks')->item(0);
        $links = array();
        
		// Search link information
        if ( $searchLinkNode ) {
            $linkNodes = $searchLinkNode->getElementsByTagNameNS(WP_NAMESPACE,'link');
            for ( $i=0; $i<$linkNodes->length; $i++ ) {
                $node = $linkNodes->item($i);
                $links[ $node->getAttributeNS(WP_NAMESPACE,'linktext') ] = $node->nodeValue;
            }
        }
        $this->search_links = $links;
        
		// Create the listing objects
        if ( $this->record_count > 0 ) {
            $listings = array();
            $listingsNode = $root->getElementsByTagNameNS(WP_NAMESPACE,'listings')->item(0);
            $listingNodeList = $listingsNode->getElementsByTagNameNS(WP_NAMESPACE,'listing');
            for( $j=0; $j<$listingNodeList->length; $j++ ) {
                array_push( $listings, new Net_WhitePages_Listing( $listingNodeList->item($j) ) );
            }
            $this->listings = $listings;
        }
    }

}
    
/**
 * Net_WhitePages_Listing - Object class used to store the data for each
 *   listing retrieved from the WhitePages.com API
 */
class Net_WhitePages_Listing {
    
	/**
	 * The Request object parameters
	 */
    private $_params;
    
	/**
	 * Class Constructor
	 *
	 * @param DOMElement $node listing node
	 */
    public function __construct( $node ) {
        $this->_params = array();
        
		// Listing meta data
        $listingmeta = $node->getElementsByTagNameNS(WP_NAMESPACE,'listingmeta')->item(0);
        $metaNodeList = $listingmeta->childNodes;
        for ( $i=0; $i<$metaNodeList->length; $i++ ) {
            $n = $metaNodeList->item($i);
            if ( $n->localName == 'moreinfolinks' ) {
                $moreinfolinks = array();
                
                $linksNode = $n->getElementsByTagNameNS(WP_NAMESPACE,'link');
                for ( $j=0; $j<$linksNode->length; $j++ ) {
                    $link = $linksNode->item($j);
                    $moreinfolinks[ $link->getAttributeNS(WP_NAMESPACE,'linktext') ] = $link->nodeValue;
                }
                
                $this->moreinfolinks = $moreinfolinks;
            }
            else if ( $n->localName ) {
                $this->_params[$n->localName] = $n->nodeValue;
            }
        }
        
		// Listing address information
        $addressNode = $node->getElementsByTagNameNS(WP_NAMESPACE,'address')->item(0);
        $this->deliverable = $addressNode->getAttributeNS(WP_NAMESPACE,'deliverable');
        $addrNodeList = $addressNode->childNodes;
        for ( $i=0; $i<$addrNodeList->length; $i++ ) {
            $n = $addrNodeList->item($i);
            if ( $n->localName ) {
                $this->_params[$n->localName] = $n->nodeValue;
            }
        }
        
		// Listing geographic data
		$geosNode = $node->getElementsByTagNameNS(WP_NAMESPACE,'geodata')->item(0);
        $geosNodeList = $geosNode->childNodes;
        for ( $i=0; $i<$geosNodeList->length; $i++ ) {
            $n = $geosNodeList->item($i);
            if ( $n->localName ) {
                $this->_params[$n->localName] = $n->nodeValue;
            }
        }
        
		// Listing business data
        $businessNode = $node->getElementsByTagNameNS(WP_NAMESPACE,'business')->item(0);
        if ( $businessNode ) {
            $n = $businessNode->getElementsByTagNameNS(WP_NAMESPACE,'businessname')->item(0);
            $this->businessname = $n->nodeValue;
        }
        
		// The people in the listing
        $persons = array();
        $peopleNode = $node->getElementsByTagNameNS(WP_NAMESPACE,'people')->item(0);
        if ( $peopleNode ) {
            $personNodeList = $peopleNode->getElementsByTagNameNS(WP_NAMESPACE,'person');
            for ( $i=0; $i<$personNodeList->length; $i++ ) {
                $person = array();
                $personNode = $personNodeList->item($i);
                $nl = $personNode->childNodes;
                for ( $j=0; $j<$nl->length; $j++ ) {
                    $n0 = $nl->item($j);
                    if ( $n0->localName ) {
                        $person[$n0->localName] = $n0->nodeValue;
                    }
                }
                $person['rank'] = $personNode->getAttributeNS(WP_NAMESPACE,'rank');
                array_push($persons,$person);
            }
        }
        $this->persons = $persons;
        
		// The phone numbers for the listing
        $phones = array();
        $phonenumbersNode = $node->getElementsByTagNameNS(WP_NAMESPACE,'phonenumbers')->item(0);
        if ( $phonenumbersNode ) {
            $phoneNodeList = $phonenumbersNode->getElementsByTagNameNS(WP_NAMESPACE,'phone');
            for ( $i=0; $i<$phoneNodeList->length; $i++ ) {
                $phone = array();
                $phoneNode = $phoneNodeList->item($i);
                $nl = $phoneNode->childNodes;
                for ( $j=0; $j<$nl->length; $j++ ) {
                    $n0 = $nl->item($j);
                    if ( $n0->localName ) {
                        $phone[$n0->localName] = $n0->nodeValue;
                    }
                }
                $phone['rank'] = $phoneNode->getAttributeNS(WP_NAMESPACE,'rank');
                $phone['type'] = $phoneNode->getAttributeNS(WP_NAMESPACE,'type');
                array_push($phones,$phone);
            }
        }
        $this->phones = $phones;
    }
    
	/**
	 * __set - override used to set object parameters
	 *
	 * @param string $key name of parameter
	 * @param mixed parameter content
	 */
    public function __set($key,$val) {
        $this->_params[$key] = $val;
    }
    
	/**
	 * __get - override used to set object parameters
	 *
	 * @param string $key name of parameter
	 * @return mixed parameter content
	 */
    public function __get($key) {
        if ( isset( $this->_params[$key] ) ) {
            return $this->_params[$key];
        }
        else {
            return false;
        }
    }
    
}

